package com.mall.b2c.domain.order;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.mall.b2c.domain.store.StoreDomain;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import com.mall.b2c.domain.delivery.DeliveryMethodDomain;
import com.mall.b2c.domain.member.MemberDomain;
import com.mall.b2c.enums.OrderStatus;
import com.mall.b2c.enums.PayStatus;
import com.mall.b2c.enums.RefundStatus;
import com.mall.b2c.enums.ShipStatus;
import com.mall.common.domain.BaseEntity;
import com.mall.common.domain.component.PaymentTypeDomain;
import com.mall.common.domain.manage.S_userDomain;
import com.mall.common.enums.PayType;

/**
 * 订单
 */
@Entity
@Table(name = "b2c_order")
public class OrderDomain extends BaseEntity {
	private static final long serialVersionUID = -1603477216132531976L;

	private String orderNo;//订单编号
	private BigDecimal totalAmount;//下单时订单金额
	private Date feeDate;// 付款日期
	private BigDecimal shipFee;//快递费
	private BigDecimal deposit;//使用余额
	private BigDecimal cash;//使用现金

	private Boolean isDelete;//是否删除
	private Date expired;//过期时间
	private Date lockExpired;//后台订单操作锁定过期时间
	
	private PayStatus payStatus;//付款状态
	private ShipStatus shipStatus;//发货状态
	private OrderStatus orderStatus;// 订单状态

	private PayType payType;//支付类型
	private PaymentTypeDomain paymentType;// 支付方式
	private String paymentTypeName;//支付方式名称
	private MemberDomain member;//会员
	private S_userDomain operator; //当前操作者
	
	private String erpCode;
	private String tradeNo;//支付编号
	private String postscript;//附言
	
	private Boolean isInvoice;// 是否开票
	private Integer invoiceType;// 发票类型：1.个人 2.单位
	private String invoiceTitle;//发票抬头
	private String consignee; //收货人
	private Long areaId; //收货地区ID
	private String areaName; //收货人地区
	private String address;// 收货人地址
	private String contact;// 收货人联系方式
	private String zipCode;// 收货人邮编

	private StoreDomain store;
	private DeliveryMethodDomain deliveryMethod; //配送方式
	
	private Set<OrderItemDomain> orderItems; //订单项
	private Set<OrderLogDomain> orderLogs; //订单日志
	private Set<ShippingDomain> shippings; //发货单（一个订单可分多次发货）
	private Set<VouchersDomain> vouchers; //付款单

	/**
	 * 是否全部已发货，补发货时用作判读
	 * @return
	 */
	@Transient
	public Boolean getAllShiped(){
		Integer buyQuantity = getQuantity();
		return buyQuantity != 0 &&  buyQuantity == getShipedQuantity();
	}

	@Transient
	public Boolean getHasRefunded() {
		if(orderItems != null){
			for(OrderItemDomain item : orderItems){
				RefundDomain refund = item.getRefund();
				if(refund != null && refund.getRefundStatus() != RefundStatus.refuse){
					return true;
				}
			}
		}
		return false;
	}

	/**
	 *  是否所有订单项退款且完成退款
	 * @return
	 */
	@Transient
	public Boolean getAllOrderItemToRefundAndFinished() {
		if(CollectionUtils.isEmpty(orderItems)){
			return false;
		} else {
			for(OrderItemDomain item : orderItems){
				RefundDomain refund = item.getRefund();
				if(refund == null
						|| !RefundStatus.finish.equals(refund.getRefundStatus())
						|| refund.getQuantity() != item.getQuantity()){
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 订单商品总重量
	 * @return
	 */
	@Transient
	public BigDecimal getWeight(){
		BigDecimal total = BigDecimal.ZERO;
		for(OrderItemDomain item : orderItems){
			total = total.add(item.getTotalWeight());
		}
		return total;
	}
	
	/**
	 * 已发货数量
	 * @return
	 */
	@Transient
	public Integer getShipedQuantity(){
		int quantity = 0 ; 
		for(OrderItemDomain item : orderItems){
			quantity += item.getShippedQuantity();
		}
		return quantity;
	}
	
	@Transient
	public Integer getQuantity(){
		int quantity = 0 ;
		if(!CollectionUtils.isEmpty(orderItems)) {
			for (OrderItemDomain item : orderItems) {
				quantity += item.getQuantity();
			}
		}
		return quantity;
	}
	
	@Transient
	public BigDecimal getRemaind(){
		BigDecimal total = this.getAmount();
		if(deposit != null){
			total = total.subtract(deposit);
		}
		if(cash != null){
			total = total.subtract(cash);
		}
		return total;
	}

	/**
	 * 订单是否已过期
	 */
	@Transient
	public boolean getIsExpired(){
		return expired != null && new Date().after(expired);
	}
	
	/**
	 * 订单是否被锁定
	 * @param user
	 * @return
	 */
	@Transient
	public boolean isLocked(String username){
		if(lockExpired == null){
			return false;
		}
		if(new Date().after(lockExpired)){
			return false;
		}
		if(operator == null){
			return false;
		}
		return !StringUtils.equals(operator.getUsername(), username);
	}
	
	@Transient
	public BigDecimal getAmount() {
		if(totalAmount != null && totalAmount.signum() > 0) {
			return totalAmount;
		}
		BigDecimal amount = BigDecimal.ZERO;
		if(!CollectionUtils.isEmpty(orderItems)) {
			for(OrderItemDomain orderItem : orderItems) {
				amount = amount.add(orderItem.getSubtotal());
			}
		}
		return amount;
	}
	
	@Transient
	public String getOrderInfo(){
		if(orderItems.isEmpty()){
			return "";
		}
		OrderItemDomain item = orderItems.iterator().next();
		return item.getProductName() + (orderItems.size() > 1?"等":"");
	}

	public String getOrderNo() {
		return orderNo;
	}

	public void setOrderNo(String orderNo) {
		this.orderNo = orderNo;
	}

	public String getErpCode() {
		return erpCode;
	}

	public void setErpCode(String erpCode) {
		this.erpCode = erpCode;
	}

	public Boolean getIsInvoice() {
		return isInvoice;
	}

	public void setIsInvoice(Boolean isInvoice) {
		this.isInvoice = isInvoice;
	}

	public Integer getInvoiceType() {
		return invoiceType;
	}

	public void setInvoiceType(Integer invoiceType) {
		this.invoiceType = invoiceType;
	}

	public Date getFeeDate() {
		return feeDate;
	}

	public void setFeeDate(Date feeDate) {
		this.feeDate = feeDate;
	}

	@ManyToOne(fetch=FetchType.LAZY)
	public PaymentTypeDomain getPaymentType() {
		return paymentType;
	}

	public void setPaymentType(PaymentTypeDomain paymentType) {
		this.paymentType = paymentType;
	}

	public String getPaymentTypeName() {
		return paymentTypeName;
	}

	public void setPaymentTypeName(String paymentTypeName) {
		this.paymentTypeName = paymentTypeName;
	}

	@Enumerated
	@Column(nullable = false)
	public OrderStatus getOrderStatus() {
		return orderStatus;
	}

	public void setOrderStatus(OrderStatus orderStatus) {
		this.orderStatus = orderStatus;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "member_id")
	public MemberDomain getMember() {
		return member;
	}

	public void setMember(MemberDomain member) {
		this.member = member;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "order", cascade = {CascadeType.ALL})
	@OrderBy("validDate")
	public Set<OrderItemDomain> getOrderItems() {
		return orderItems;
	}
	public void setOrderItems(Set<OrderItemDomain> orderItems) {
		this.orderItems = orderItems;
	}

	public Boolean getIsDelete() {
		return isDelete;
	}

	public void setIsDelete(Boolean isDelete) {
		this.isDelete = isDelete;
	}

	public BigDecimal getTotalAmount() {
		return totalAmount;
	}

	public void setTotalAmount(BigDecimal totalAmount) {
		this.totalAmount = totalAmount;
	}

	public BigDecimal getDeposit() {
		return deposit;
	}

	public void setDeposit(BigDecimal deposit) {
		this.deposit = deposit;
	}

	public BigDecimal getCash() {
		return cash;
	}

	public void setCash(BigDecimal cash) {
		this.cash = cash;
	}

	public Date getExpired() {
		return expired;
	}

	public void setExpired(Date expired) {
		this.expired = expired;
	}

	public PayStatus getPayStatus() {
		return payStatus;
	}

	public void setPayStatus(PayStatus payStatus) {
		this.payStatus = payStatus;
	}

	public ShipStatus getShipStatus() {
		return shipStatus;
	}

	public void setShipStatus(ShipStatus shipStatus) {
		this.shipStatus = shipStatus;
	}

	public PayType getPayType() {
		return payType;
	}

	public void setPayType(PayType payType) {
		this.payType = payType;
	}

	public String getTradeNo() {
		return tradeNo;
	}

	public void setTradeNo(String tradeNo) {
		this.tradeNo = tradeNo;
	}

	public BigDecimal getShipFee() {
		return shipFee;
	}

	public void setShipFee(BigDecimal shipFee) {
		this.shipFee = shipFee;
	}
	
	public Date getLockExpired() {
		return lockExpired;
	}

	public void setLockExpired(Date lockExpired) {
		this.lockExpired = lockExpired;
	}

	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="operator_id")
	public S_userDomain getOperator() {
		return operator;
	}

	public void setOperator(S_userDomain operator) {
		this.operator = operator;
	}

	public String getPostscript() {
		return postscript;
	}

	public void setPostscript(String postscript) {
		this.postscript = postscript;
	}

	public String getConsignee() {
		return consignee;
	}

	public void setConsignee(String consignee) {
		this.consignee = consignee;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getContact() {
		return contact;
	}

	public void setContact(String contact) {
		this.contact = contact;
	}

	public String getZipCode() {
		return zipCode;
	}

	public void setZipCode(String zipCode) {
		this.zipCode = zipCode;
	}
	
	public Long getAreaId() {
		return areaId;
	}

	public void setAreaId(Long areaId) {
		this.areaId = areaId;
	}

	public String getAreaName() {
		return areaName;
	}

	public void setAreaName(String areaName) {
		this.areaName = areaName;
	}

	@ManyToOne(fetch=FetchType.LAZY)
	public DeliveryMethodDomain getDeliveryMethod() {
		return deliveryMethod;
	}

	public void setDeliveryMethod(DeliveryMethodDomain deliveryMethod) {
		this.deliveryMethod = deliveryMethod;
	}

	@OneToMany(fetch=FetchType.LAZY, mappedBy="order")
	@OrderBy("createDate")
	public Set<OrderLogDomain> getOrderLogs() {
		return orderLogs;
	}

	public void setOrderLogs(Set<OrderLogDomain> orderLogs) {
		this.orderLogs = orderLogs;
	}

	public String getInvoiceTitle() {
		return invoiceTitle;
	}

	public void setInvoiceTitle(String invoiceTitle) {
		this.invoiceTitle = invoiceTitle;
	}
	
	@OneToMany(fetch=FetchType.LAZY, mappedBy="order")
	public Set<ShippingDomain> getShippings() {
		return shippings;
	}

	public void setShippings(Set<ShippingDomain> shippings) {
		this.shippings = shippings;
	}
	
	@OneToMany(fetch=FetchType.LAZY, mappedBy="order")
	public Set<VouchersDomain> getVouchers() {
		return vouchers;
	}
	
	public void setVouchers(Set<VouchersDomain> vouchers) {
		this.vouchers = vouchers;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "store_id")
	public StoreDomain getStore() {
		return store;
	}

	public void setStore(StoreDomain store) {
		this.store = store;
	}
}
